package edu.mse.camel.client.whiteboard.gef.ui.editpart;

import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.editparts.AbstractTreeEditPart;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.views.properties.IPropertySource;

import edu.mse.camel.client.whiteboard.gef.ui.WhiteboardPlugin;
import edu.mse.camel.client.whiteboard.gef.ui.properties.ShapePropertySource;
import edu.mse.camel.client.whiteboard.gef.whiteboard.EllipticalShape;
import edu.mse.camel.client.whiteboard.gef.whiteboard.RectangularShape;
import edu.mse.camel.client.whiteboard.gef.whiteboard.Shape;

/**
 * TreeEditPart used for Shape instances (more specific for EllipticalShape and
 * RectangularShape instances). This is used in the Outline View of the ShapesEditor.
 * <p>This edit part must implement the PropertyChangeListener interface, 
 * so it can be notified of property changes in the corresponding model element.
 * </p>
 * 
 * @author darpan
 */
class ShapeTreeEditPart extends AbstractTreeEditPart implements Adapter {
	private Notifier target;
	
	/**
	 * Create a new instance of this edit part using the given model element.
	 * @param model a non-null Shapes instance
	 */
	ShapeTreeEditPart(Shape model) {
		super(model);
	}
	
	private void hookIntoModel(EObject model) {
		if(model != null) {
			model.eAdapters().add(this);
		}
	}
	
	private void unhookFromModel(EObject model) {
		if(model != null) {
			model.eAdapters().remove(this);
		}
	}
	
	/**
	 * Upon activation, attach to the model element as a property change listener.
	 */
	public void activate() {
		if (!isActive()) {
			hookIntoModel(getCastedModel());
			super.activate();
		}
	}
	
	public Object getAdapter(Class key) {
		if (IPropertySource.class == key)
			return new ShapePropertySource(getModel());
		return super.getAdapter(key);
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractTreeEditPart#createEditPolicies()
	 */
	protected void createEditPolicies() {
		// allow removal of the associated model element
		installEditPolicy(EditPolicy.COMPONENT_ROLE, new ShapeComponentEditPolicy());
	}
	
	/**
	 * Upon deactivation, detach from the model element as a property change listener.
	 */
	public void deactivate() {
		if (isActive()) {
			unhookFromModel(getCastedModel());
			super.deactivate();
		}
	}
	
	private Shape getCastedModel() {
		return (Shape) getModel();
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractTreeEditPart#getImage()
	 */
	protected Image getImage() {
		return createImageForModel(getCastedModel());
	}
	
	protected Image createImageForModel(Shape shape) {
		Image image = null;
		if(shape instanceof RectangularShape) {
			image = WhiteboardPlugin.getImageDescriptor("icons/rectangle16.gif").createImage();
		}
		if(shape instanceof EllipticalShape) {
			image = WhiteboardPlugin.getImageDescriptor("icons/ellipse16.gif").createImage();
		}
		return image;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractTreeEditPart#getText()
	 */
	protected String getText() {
		return getCastedModel().toString();
	}
	
	public void notifyChanged(Notification notification) {
		refreshVisuals(); // this will cause an invocation of getImage() and getText(), see below
	}
	
	public Notifier getTarget() {
		return target;
	}
	
	public void setTarget(Notifier newTarget) {
		target = newTarget;
	}
	
	public boolean isAdapterForType(Object type) {
		return getModel() == type;
	}
}